#include "network_base.h"
#include "message_buffer.h"
#include "game_server.h"
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#ifndef _WIN32
#include <netinet/in.h>
# ifdef _XOPEN_SOURCE_EXTENDED
#  include <arpa/inet.h>
# endif
#include <sys/socket.h>
#endif
#include <iostream>

using namespace std;

std::map<int, NetworkSessionBase*> NetworkBase::_sessions_dict;//连接索引

NetworkBase::NetworkBase(event_base * event_base)
	: AsyncTimer(event_base)
	, _event_base(event_base)
{
	InitTimer(_heartbeat_timer, 10, [this] {
		//检查心跳
		auto itr = _sessions.begin();
		while (itr != _sessions.end())
		{
			auto info = *itr;
			if (info->_heartbeat)
			{
				info->_heartbeat = false;
			}
			else
			{
				cout << "clear: " << info->_fd << " ptr: " << info << endl;
				info->Destroy();
				if (info->_is_destroy)
				{
					cout << "delete: " << info->_fd << " ptr: " << info << endl;
					itr = _sessions.erase(itr);
					delete info;
					continue;
				}
			}
			++itr;
		}
	}, true);
	_heartbeat_timer.start();
}

bool NetworkBase::InitListen(short port)
{
	struct sockaddr_in sin;
	if (!_event_base) {
		fprintf(stderr, "Could not initialize libevent!\n");
		return false;
	}

	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);

	_listener = evconnlistener_new_bind(_event_base, listener_cb, this,
		LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, -1,
		(struct sockaddr*)&sin,
		sizeof(sin));

	if (!_listener) {
		fprintf(stderr, "Could not create a listener!\n");
		return false;
	}
	return true;
}

void NetworkBase::listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
	struct sockaddr *sa, int socklen, void *user_data)
{
	NetworkBase *base = (NetworkBase *)user_data;
	if (fd < 0)
	{
		fprintf(stderr, "fd < 0!");
		return;
	}
	auto conn = base->NewSession(fd);
	if (conn != nullptr && conn->InitAccept(fd))
	{
		base->_sessions_dict[fd] = conn;
		base->_sessions.push_back(conn);
	}
}
bool NetworkBase::DelSession(NetworkSessionBase* base)
{
	//指针不为空
	if (base)
	{
		base->Destroy();
		auto itr = _sessions_dict.find(base->_fd);
		//如果在索引内
		if (itr != _sessions_dict.end() && base == itr->second)
		{
			_sessions_dict.erase(itr);
		}
	}
	return false;
}

NetworkSessionBase * NetworkBase::operator[](int fd)
{
	auto itr = _sessions_dict.find(fd);
	if (itr != _sessions_dict.end())
	{
		return itr->second;
	}
	return nullptr;
}

bool NetworkSessionBase::InitAccept(int fd)
{
	_fd = fd;
	_bev = bufferevent_socket_new(_event_base, _fd, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
	if (!_bev) {
		fprintf(stderr, "Error constructing bufferevent!");
		event_base_loopbreak(_event_base);
		return false;
	}
	bufferevent_setcb(_bev, conn_readcb, conn_writecb, conn_eventcb, this);
	bufferevent_enable(_bev, EV_WRITE);
	bufferevent_enable(_bev, EV_READ | EV_PERSIST);
	return true;
}

NetworkSessionBase* NetworkBase::NewSession(int fd)
{
	return new NetworkSessionBase(_event_base);
}

void NetworkSessionBase::conn_readcb(struct bufferevent *bev, void *user_data)
{
	cout << "readcd" << endl;
	static char msg[4096];
	size_t len = bufferevent_read(bev, msg, sizeof(msg));
	cout << "recv len:" << len << endl;
	NetworkSessionBase* base = (NetworkSessionBase*)user_data;
	if (!base->_per_destroy && !base->_is_destroy)
	{
		base->_rbuf.Write(msg, len);
		base->_heartbeat = (0 == base->HandleMessage());
		cout << "bufsize: " << base->_rbuf.GetBufferSize() << endl;
		cout << "bufspace: " << base->_rbuf.GetRemainingSpace() << endl;
		base->_rbuf.Normalize();
	}
}

void NetworkSessionBase::conn_eventcb(struct bufferevent *bev, short events, void *user_data)
{
	NetworkSessionBase* self = (NetworkSessionBase*)user_data;
	if (events & BEV_EVENT_EOF) {
		printf("Connection closed.\n");
	}
	else if (events & BEV_EVENT_ERROR) {
		printf("Got an error on the connection: %s\n",
			strerror(errno));/*XXX win32*/
	}
	self->Destroy();
}

void NetworkSessionBase::conn_writecb(bufferevent * bev, void * user_data)
{
	NetworkSessionBase* self = (NetworkSessionBase*)user_data;
	if (self->_per_destroy)
	{
		struct evbuffer *output = bufferevent_get_output(bev);
		if (evbuffer_get_length(output) == 0) {
			printf("evbuffer_get_length = 0\n");
			self->_is_destroy = true;
			self->Free();
		}
	}
}

int NetworkSessionBase::HandleMessage()
{
	std::string str = _rbuf.Read(_rbuf.GetActiveSize());
	cout << "read:" << str << endl;
	if (str == "exit")
	{
		Destroy();
	}
	Send(str);
	Destroy();
	return 0;
}

void NetworkSessionBase::Send(const std::string & str)
{
	Send(str.c_str(), str.size());
}

void NetworkSessionBase::Send(const char * data, size_t length)
{
	SendBase(data, length);
}

void NetworkSessionBase::SendBase(const char * data, size_t length)
{
	if (!_per_destroy && !_is_destroy)
	{
		bufferevent_write(_bev, data, length);
	}
}

void NetworkSessionBase::Destroy()
{
	if (!_per_destroy && !_is_destroy)
	{
		auto itr = NetworkBase::_sessions_dict.find(_fd);
		//如果在索引内
		if (itr != NetworkBase::_sessions_dict.end() && this == itr->second)
		{
			cout << "erase index: " << (int)this << endl;
			NetworkBase::_sessions_dict.erase(itr);
			BeforeDestroy();
		}
		struct evbuffer *output = bufferevent_get_output(_bev);
		auto len = evbuffer_get_length(output);
		//所有内容都已经发送完毕
		if (len == 0) {
			_is_destroy = true;
			Free();
		}
		else
		{
			_per_destroy = true;
		}
		printf("Destroy len = %d\n", len);
	}
}

void NetworkSessionBase::Free()
{
	cout << "close!" << endl;
	bufferevent_free(_bev);
}
